package com.sbl.factory;



import com.sbl.service.IAccountService;
import com.sbl.utils.TransactionManager;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK自带的动态代理，默认使用这种
 *
 * 用于创建Service的代理对象的工厂
 *  动态代理：
 *      特点：字节码随用随创建，随用随加载
 *      作用：不修改源码的基础上对方法进行增强
 *   分类：
 *      基于接口的动态代理
 *      基于子类的动态代理
 *   基于接口的动态代理：
 *          涉及的类：Proxy
 *          提供者：JDK官方
 *   如何创建代理对象：
 *         使用Proxy类中的newProxyInstance方法
 *   创建代理对象的要求：
 *        被代理类 ====最少实现一个接口===== ，如果没有则不能使用
 *    newProxyInstance方法的参数：
 *    newProxyInstance( ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
 *          1. ClassLoader：类加载器，它是用于加载代理对象字节码。和被代理对象使用相同
 *          的类加载器-固定写法
 *          2. Class[]，字节码数组，它是用于让代理对象和被代理对象有相同的方法-固定写法
 *          3. InvocationHandler：用于提供增强的代码。它是让我们写如何代理
 *
 *
 */
public class BeanFactory {

    private IAccountService accountService;

    private TransactionManager txManager;

    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }


    public final void setAccountService(IAccountService accountService) {
        this.accountService = accountService;
    }

    /**
     * 获取Service代理对象
     *  执行被代理对象（它的方法就是切点了吧，被增强）的任何接口方法都会经过该方法
     *  代理对象调用方法的时候，invoke方法会执行，被代理对象原来的方法
     * @return
     */
    public IAccountService getAccountService() {
        return (IAccountService)Proxy.newProxyInstance(accountService.getClass().getClassLoader(),
                accountService.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     *
                     * 添加事务的支持
                     * 作用：执行被代理对象的任何接口方法都会经过该方法
                     * 方法参数的含义
                     * @param proxy   代理对象的引用
                     * @param method  当前执行的方法
                     * @param args    当前执行方法所需的参数
                     * @return        和被代理对象方法有相同的返回值
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        if("test".equals(method.getName())){
                            return method.invoke(accountService,args);
                        }
                        //提供增强的代码
                        Object rtValue = null;
                        try {
                            System.out.println("代理中的方法执行....");
                            //1.开启事务|连接开启
                            txManager.beginTransaction();
                            //2.执行操作（有多个方法的时候，可以method.getName()判断）
                            //所有动态代理类所调用的方法，都会交给该方法处理
                            rtValue = method.invoke(accountService, args);
                            //3.提交事务
                            txManager.commit();
                            //4.返回结果
                            return rtValue;
                        } catch (Exception e) {
                            //5.回滚操作|还是连接的回滚
                            txManager.rollback();
                            throw new RuntimeException(e);
                        } finally {
                            //6.释放连接
                            txManager.release();
                        }
                    }
                });

    }
}
